package com.dgsrz.demo.activity;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;
import com.dgsrz.demo.R;
import com.dgsrz.demo.game.Slider;
import com.dgsrz.demo.primitive.SliderContainer;
import com.dgsrz.demo.texture.GradientTexture;
import com.dgsrz.demo.util.FPSLogger;
import com.dgsrz.demo.util.GameUtils;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11ExtensionPack;

/**
 * Created by dgsrz on 15/7/2.
 */
public class DemoGameScene {

    private static final int TEXTURE_WIDTH   = 128;
    private static final int TEXTURE_HEIGHT  = 1;

    private Activity mContext;

    private GradientTexture mGradientTexture;
    private Slider          mSlider;

    private FPSLogger  mLogger     = FPSLogger.INSTANCE;
    private RenderMode mRenderMode = RenderMode.SLIDER;

    public DemoGameScene(Activity context) {
        this.mContext = context;
    }

    /**
     * Settings this will change the behaviour of this demo.
     *
     * @param mode Expected mode
     */
    public void setRenderMode(RenderMode mode) {
        this.mRenderMode = mode;
    }

    public enum RenderMode {
        TEXTURE, SLIDER
    }

    public final Slider getSlider() {
        return mSlider;
    }

    public class Renderer implements GLSurfaceView.Renderer {

        private boolean mContextSupportsFrameBufferObject;

        private int mSurfaceWidth;
        private int mSurfaceHeight;

        private int mRectangleTexture;
        private int mRectangleTarget;

        private int mSliderTexture;
        private int mSliderTarget;

        private int mBackdropTexture;

        private SliderContainer mOnScreenLayer;

        @Override
        public void onDrawFrame(GL10 gl) {
            GameUtils.checkGLErrors(gl);
            if (mContextSupportsFrameBufferObject) {
                GL11ExtensionPack gl11ep = (GL11ExtensionPack) gl;

                if (mRenderMode == RenderMode.TEXTURE) {
                    drawTexture(gl, mSurfaceWidth, mSurfaceHeight);

                } else if (mRenderMode == RenderMode.SLIDER) {
                    gl11ep.glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, mRectangleTarget);
                    drawTexture(gl, TEXTURE_WIDTH, TEXTURE_HEIGHT);

                    gl11ep.glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, mSliderTarget);
                    // limit to 512 * 512 can solve NPOT texture problem and enhance a little performance
                    drawSlider(gl, mSurfaceWidth, mSurfaceHeight);

                    gl11ep.glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, 0);
                    drawOnScreen(gl, mSurfaceWidth, mSurfaceHeight);
                }
            } else {
                gl.glClearColor(0, 0.5f, 1f, 0);
                gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
            }
            mLogger.finishGLDraw();
        }

        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            GameUtils.checkGLErrors(gl);
            mSurfaceWidth = width;
            mSurfaceHeight = height;
            gl.glViewport(0, 0, width, height);

            mRectangleTexture = GameUtils.createTargetTexture(gl, TEXTURE_WIDTH, TEXTURE_HEIGHT);
            mRectangleTarget = GameUtils.createFrameBuffer(gl, TEXTURE_WIDTH, TEXTURE_HEIGHT, mRectangleTexture);

            mSliderTexture = GameUtils.createTargetTexture(gl, mSurfaceWidth, mSurfaceHeight);
            mSliderTarget = GameUtils.createFrameBuffer(gl, mSurfaceWidth, mSurfaceHeight, mSliderTexture);

            mOnScreenLayer = new SliderContainer(gl, mSurfaceWidth, mSurfaceHeight);
        }

        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            mContextSupportsFrameBufferObject = GameUtils.checkExtensionCompatibility(gl, GameUtils.GL_EXT_FBO);
            if (mContextSupportsFrameBufferObject) {
                mBackdropTexture = loadBackground(gl, mContext);
                mGradientTexture = new GradientTexture(gl);

                mSlider = new Slider(mContext, gl);
                // mSlider.setSliderCommand("96,240,0,0,0,B|240:96|400:96|544:240,1,0");
                mSlider.setSliderCommand("464,340,410117,6,0,B|497:298|527:255|539:144|473:78|424:52|334:48|334:48|299:59|231:77|166:94|63:61|1:30|1:30|33:84|44:103|104:134|189:145|189:145|148:169|105:177|72:182|72:182|108:203|164:213|224:201|224:201|205:222|172:243|138:255|138:255|184:265|228:261|257:254|257:254|242:286|220:302|220:302|273:309|323:307|370:298|413:282|425:243|425:243|454:169|392:78|275:90|240:149|287:231|333:234|348:215|348:215,1,2096.22747971515");
                mSlider.getPathPoints();
            }
        }

        private void drawOnScreen(GL10 gl, int width, int height) {
            gl.glViewport(0, 0, width, height);
            gl.glMatrixMode(GL10.GL_PROJECTION);
            gl.glLoadIdentity();
            gl.glOrthof(0, width, height, 0, 0, 65536.0f);

            gl.glClearColor(0, 0.5f, 1f, 0);
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

            gl.glMatrixMode(GL10.GL_MODELVIEW);
            gl.glLoadIdentity();

            gl.glEnable(GL10.GL_TEXTURE_2D);

            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
            gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

            gl.glDisable(GL10.GL_DEPTH_TEST);
            gl.glEnable(GL10.GL_BLEND);
            gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);

            gl.glBindTexture(GL10.GL_TEXTURE_2D, mBackdropTexture);
            mOnScreenLayer.drawPrimitives();

            gl.glBindTexture(GL10.GL_TEXTURE_2D, mSliderTexture);
            gl.glColor4f(1, 1, 1, mSlider.getAlpha());
            mOnScreenLayer.drawPrimitives();
            gl.glColor4f(1, 1, 1, 1f);

            gl.glDisable(GL10.GL_BLEND);

            gl.glBindTexture(GL10.GL_TEXTURE_2D, 0);
            gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
            gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        }

        private void drawSlider(GL10 gl, int width, int height) {
            gl.glViewport(0, 0, width, height);
            gl.glMatrixMode(GL10.GL_PROJECTION);
            gl.glLoadIdentity();
            gl.glOrthof(0, width, height, 0, 0, 65536.0f);

            /*
            For reusing purpose, disabled clear operation before draw onto framebuffer.
            May enhance performance.
            gl.glClearColor(0, 0, 0, 0);
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
            */
            gl.glBindTexture(GL10.GL_TEXTURE_2D, mRectangleTexture);

            gl.glMatrixMode(GL10.GL_MODELVIEW);
            gl.glLoadIdentity();

            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
            gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

            gl.glActiveTexture(GL10.GL_TEXTURE0);

            gl.glDisable(GL10.GL_BLEND);
            gl.glEnable(GL10.GL_DEPTH_TEST);
            gl.glDepthFunc(GL10.GL_LEQUAL);

            mSlider.drawObject();

            gl.glDisable(GL10.GL_DEPTH_TEST);

            gl.glBindTexture(GL10.GL_TEXTURE_2D, 0);
            gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
            gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        }

        private void drawTexture(GL10 gl, int width, int height) {
            gl.glViewport(0, 0, width, height);
            gl.glMatrixMode(GL10.GL_PROJECTION);
            gl.glLoadIdentity();
            gl.glOrthof(0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f);

            gl.glClearColor(0, 0, 0, 0);
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
            gl.glMatrixMode(GL10.GL_MODELVIEW);
            gl.glLoadIdentity();

            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
            gl.glEnableClientState(GL10.GL_COLOR_ARRAY);

            gl.glDisable(GL10.GL_BLEND);
            gl.glDisable(GL10.GL_DEPTH_TEST);

            mGradientTexture.drawTexture();

            gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
            gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
        }

        private int loadBackground(GL10 gl, Context context) {
            int[] textures = new int[1];

            Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.raw.backdrop);

            gl.glGenTextures(1, textures, 0);
            gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

            GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

            bitmap.recycle();
            return textures[0];
        }
    }
}
